/*-------------------------------- Arctic Core ------------------------------
 * Copyright (C) 2013, ArcCore AB, Sweden, www.arccore.com.
 * Contact: <contact@arccore.com>
 * 
 * You may ONLY use this file:
 * 1)if you have a valid commercial ArcCore license and then in accordance with  
 * the terms contained in the written license agreement between you and ArcCore, 
 * or alternatively
 * 2)if you follow the terms found in GNU General Public License version 2 as 
 * published by the Free Software Foundation and appearing in the file 
 * LICENSE.GPL included in the packaging of this file or here 
 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
 *-------------------------------- Arctic Core -----------------------------*/

/*
 *  General requirements
 */
/** @req DCM030 */

#include "mid_S32kToAutoChip_Hal.h"

#include <string.h>
#include "Dcm.h"
#include "Dcm_Internal.h"
//#include "MemMap.h"
#if defined(USE_COMM) || (DCM_UNIT_TEST == STD_ON)
#include "ComM_Dcm.h"
#endif
#include "PduR_Dcm.h"
#include "PduR_Types.h" // OBD: for preemption cancel PDUR tx
#include "PduR.h"       // OBD: for cancel
#include "ComStack_Types.h"
//#define USE_DEBUG_PRINTF
#include "debug.h"

#define DECREMENT(timer) { if (timer > 0){timer--;} }
#define DCM_CONVERT_MS_TO_MAIN_CYCLES(x)  ((x)/DCM_MAIN_FUNCTION_PERIOD_TIME_MS)

typedef struct {
	boolean initRun;
	const Dcm_DslProtocolRowType *activeProtocol; // Points to the currently active protocol.
} DcmDsl_RunTimeDataType;

static DcmDsl_RunTimeDataType DcmDslRunTimeData = {
		.initRun = FALSE,
		.activeProtocol = NULL
};

static inline void startS3SessionTimer(Dcm_DslRunTimeProtocolParametersType *runtime, const Dcm_DslProtocolRowType *protocolRow) {
	const Dcm_DslProtocolTimingRowType *timeParams;
	timeParams = protocolRow->DslProtocolTimeLimit;
	runtime->S3ServerTimeoutCount = DCM_CONVERT_MS_TO_MAIN_CYCLES(timeParams->TimStrS3Server);
	runtime->S3ServerStarted = TRUE;
}

static inline void stopS3SessionTimer(Dcm_DslRunTimeProtocolParametersType *runtime) {
	runtime->S3ServerStarted = FALSE;
}


// - - - - - - - - - - -
//
//	This function implements the requirement DCM139 when
// 	transition from one session to another.
//
static void changeDiagnosticSession(Dcm_DslRunTimeProtocolParametersType *runtime, Dcm_SesCtrlType newSession) {

    switch (runtime->sessionControl) {
		case DCM_DEFAULT_SESSION: // "default".
			/* to set the dsp buffer to default*/
			runtime->securityLevel = DCM_SEC_LEV_LOCKED;
			break;

		case DCM_PROGRAMMING_SESSION:
			//runtime->securityLevel = DCM_SEC_LEV_L2; 
			break;
		case DCM_EXTENDED_DIAGNOSTIC_SESSION:
		case DCM_SAFTEY_SYSTEM_DIAGNOSTIC_SESSION:
		case DCM_ALL_SESSION_LEVEL:
			//runtime->securityLevel = DCM_SEC_LEV_L1; 
			runtime->securityLevel = DCM_SEC_LEV_LOCKED;
			break;

		default:
			//ASLOG("DCM", "[1]\r\n");//[1]:Old session invalid
			break;
    }

    switch (newSession) {
		case DCM_DEFAULT_SESSION: // "default".
			runtime->sessionControl = newSession;
			break;
		case DCM_PROGRAMMING_SESSION:
		case DCM_EXTENDED_DIAGNOSTIC_SESSION:
		case DCM_SAFTEY_SYSTEM_DIAGNOSTIC_SESSION:
		case DCM_ALL_SESSION_LEVEL:
			runtime->sessionControl = newSession;
			break;

		default:
			//ASLOG("DCM", "[2]\r\n");//[2] New session invalid
			break;
    }
	DspInit(FALSE);
    DspResetDiagnosticActivityOnSessionChange(newSession);
}

// - - - - - - - - - - -

void DslResetSessionTimeoutTimer(void) {
	const Dcm_DslProtocolRowType *activeProtocol;
	Dcm_DslRunTimeProtocolParametersType *runtime;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if( NULL != activeProtocol ) {
		runtime = activeProtocol->DslRunTimeProtocolParameters;
		startS3SessionTimer(runtime, activeProtocol); /** @req DCM141 */
	}
}

// - - - - - - - - - - -

void DslGetCurrentServiceTable(const Dcm_DsdServiceTableType **currentServiceTable) { /** @req DCM195 */
	const Dcm_DslProtocolRowType *activeProtocol;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if (activeProtocol != NULL) {
		*currentServiceTable = activeProtocol->DslProtocolSIDTable;
	}
}

// - - - - - - - - - - -

Std_ReturnType DslGetActiveProtocol(Dcm_ProtocolType *protocolId) { /** @req DCM340 */
	Std_ReturnType ret = E_NOT_OK;
	const Dcm_DslProtocolRowType *activeProtocol;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if (activeProtocol != NULL) {
		*protocolId = activeProtocol->DslProtocolID;
		ret = E_OK;
	}
	return ret;
}

// - - - - - - - - - - -

void DslSetSecurityLevel(Dcm_SecLevelType secLevel) { /** @req DCM020 */
	const Dcm_DslProtocolRowType *activeProtocol;
	Dcm_DslRunTimeProtocolParametersType *runtime;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	runtime = activeProtocol->DslRunTimeProtocolParameters;
	runtime->securityLevel = secLevel;
}

// - - - - - - - - - - -

Std_ReturnType DslGetSecurityLevel(Dcm_SecLevelType *secLevel) {  /** @req DCM020 *//** @req DCM338 */
	Std_ReturnType ret = E_NOT_OK;
	const Dcm_DslProtocolRowType *activeProtocol;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if (activeProtocol != NULL) {
		runtime = activeProtocol->DslRunTimeProtocolParameters;
		*secLevel = runtime->securityLevel;
		ret = E_OK;
	}
	return ret;
}

// - - - - - - - - - - -

void DslSetSesCtrlType(Dcm_SesCtrlType sesCtrl) {  /** @req DCM022 */
	const Dcm_DslProtocolRowType *activeProtocol;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if (activeProtocol != NULL) {
		runtime = activeProtocol->DslRunTimeProtocolParameters;
        changeDiagnosticSession(runtime, sesCtrl);
        DslResetSessionTimeoutTimer();

	}
}

// - - - - - - - - - - -

Std_ReturnType DslGetSesCtrlType(Dcm_SesCtrlType *sesCtrlType) { /** @req DCM022 *//** @req DCM339 */
	Std_ReturnType ret = E_NOT_OK;
	const Dcm_DslProtocolRowType *activeProtocol;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	activeProtocol = DcmDslRunTimeData.activeProtocol;
	if (activeProtocol != NULL) {
		runtime = activeProtocol->DslRunTimeProtocolParameters;
		*sesCtrlType = runtime->sessionControl;
		ret = E_OK;
	}
	return ret;
}

const Dcm_DspSessionRowType *getActiveSessionRow(Dcm_DslRunTimeProtocolParametersType *runtime) {
	 const Dcm_DspSessionRowType *sessionRow = Dcm_ConfigPtr->Dsp->DspSession->DspSessionRow;

	while ((sessionRow->DspSessionLevel != runtime->sessionControl) && (!sessionRow->Arc_EOL) ) {
		sessionRow++;
	}
	if( TRUE == sessionRow->Arc_EOL ) {
		/* Since we are in a session with no configuration - take any session configuration and report error */
		//ASLOG("DCM", "[3]\r\n");//[3]:DCM_CHANGE_DIAGNOSTIC_SESSION_ID, DCM_E_CONFIG_INVALID
		sessionRow = Dcm_ConfigPtr->Dsp->DspSession->DspSessionRow;
	}

	return sessionRow;
}

// - - - - - - - - - - -

static boolean findRxPduIdParentConfigurationLeafs(PduIdType dcmRxPduId,
		const Dcm_DslProtocolRxType **protocolRx,
		const Dcm_DslMainConnectionType **mainConnection,
		const Dcm_DslConnectionType **connection,
		const Dcm_DslProtocolRowType **protocolRow,
		Dcm_DslRunTimeProtocolParametersType **runtime) {

	boolean ret = FALSE;
	if (dcmRxPduId < DCM_DSL_RX_PDU_ID_LIST_LENGTH) {	// 0=phys  1=func
		*protocolRx = &Dcm_ConfigPtr->Dsl->DslProtocol->DslProtocolRxGlobalList[dcmRxPduId];
		*mainConnection = (*protocolRx)->DslMainConnectionParent;
		*connection = (*mainConnection)->DslConnectionParent;
		*protocolRow = (*connection)->DslProtocolRow;
		*runtime = (*protocolRow)->DslRunTimeProtocolParameters;
		ret = TRUE;
	}
	return ret;
}

// - - - - - - - - - - -

static boolean findTxPduIdParentConfigurationLeafs(PduIdType dcmTxPduId,
		const Dcm_DslProtocolTxType **protocolTx,
		const Dcm_DslMainConnectionType **mainConnection,
		const Dcm_DslConnectionType **connection,
		const Dcm_DslProtocolRowType **protocolRow,
		Dcm_DslRunTimeProtocolParametersType **runtime) {

	boolean ret = FALSE;
	if (dcmTxPduId < DCM_DSL_TX_PDU_ID_LIST_LENGTH) {
		*protocolTx = &Dcm_ConfigPtr->Dsl->DslProtocol->DslProtocolTxGlobalList[dcmTxPduId];
		*mainConnection = (*protocolTx)->DslMainConnectionParent;
		*connection = (*mainConnection)->DslConnectionParent;
		*protocolRow = (*connection)->DslProtocolRow;
		*runtime = (*protocolRow)->DslRunTimeProtocolParameters;
		ret = TRUE;
	}
	return ret;
}

// - - - - - - - - - - -

static inline void releaseExternalRxTxBuffers(const Dcm_DslProtocolRowType *protocolRow,
		Dcm_DslRunTimeProtocolParametersType *runtime) {

	protocolRow->DslProtocolTxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
	protocolRow->DslProtocolRxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
	runtime->externalTxBufferStatus = NOT_IN_USE; // We are waiting for DSD to return the buffer. qqq.
	runtime->externalRxBufferStatus = NOT_IN_USE; // We are waiting for DSD to return the buffer. qqq.
	protocolRow->DslProtocolTxBufferID->externalBufferRuntimeData->DcmRxPduId = DCM_INVALID_PDU_ID;
}

// - - - - - - - - - - -


static inline void releaseExternalRxTxBuffersHelper(PduIdType rxPduIdRef) {
	const Dcm_DslProtocolRxType *protocolRx = NULL;
	const Dcm_DslMainConnectionType *mainConnection = NULL;
	const Dcm_DslConnectionType *connection = NULL;
	const Dcm_DslProtocolRowType *protocolRow = NULL;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	if (findRxPduIdParentConfigurationLeafs(rxPduIdRef, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) {
		releaseExternalRxTxBuffers(protocolRow, runtime);
	}
}

// - - - - - - - - - - -

/*
 *  This function is called from the DSD module to the DSL when
 *  a response to a diagnostic request has been copied into the
 *  given TX-buffer and is ready for transmission.
 */
void DslDsdProcessingDone(PduIdType rxPduIdRef, DsdProcessingDoneResultType responseResult) {
	const Dcm_DslProtocolRxType *protocolRx = NULL;
	const Dcm_DslMainConnectionType *mainConnection = NULL;
	const Dcm_DslConnectionType *connection = NULL;
	const Dcm_DslProtocolRowType *protocolRow = NULL;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	//ASLOG("DCM", "DslDsdProcessingDone rxPduIdRef=%d\r\n", rxPduIdRef);

	if (findRxPduIdParentConfigurationLeafs(rxPduIdRef, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) {
		switch (responseResult) {
		case DSD_TX_RESPONSE_READY:
			runtime->externalTxBufferStatus = DSD_PENDING_RESPONSE_SIGNALED; /** @req DCM114 */
			break;
		case DSD_TX_RESPONSE_SUPPRESSED: /** @req DCM238 */
			//ASLOG("DCM", "[4]\r\n");//[4]:DslDsdProcessingDone called with DSD_TX_RESPONSE_SUPPRESSED.
			releaseExternalRxTxBuffersHelper(rxPduIdRef);
			break;
		default:
			//ASLOG("DCM", "[5]\r\n");//[5]:Unknown response result from DslDsdProcessingDone!
			break;
		}
	}
}

// - - - - - - - - - - -

/*
 *	This function preparing transmission of response
 *	pending message to tester.
 */
static void sendResponse(const Dcm_DslProtocolRowType *protocol,
		Dcm_NegativeResponseCodeType responseCode) {
	//Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
	const Dcm_DslProtocolRxType *protocolRx = NULL;
	const Dcm_DslMainConnectionType *mainConnection = NULL;
	const Dcm_DslConnectionType *connection = NULL;
	const Dcm_DslProtocolRowType *protocolRow = NULL;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
	Std_ReturnType transmitResult;
	
	if (findRxPduIdParentConfigurationLeafs(protocol->DslRunTimeProtocolParameters->diagReqestRxPduId, &protocolRx,	&mainConnection, &connection, &protocolRow, &runtime)) {
		if (runtime->localTxBuffer.status == NOT_IN_USE) {
		    runtime->localTxBuffer.responseCode = responseCode;
			runtime->localTxBuffer.status = PROVIDED_TO_DSD;
			runtime->localTxBuffer.buffer[0] = SID_NEGATIVE_RESPONSE;
			runtime->localTxBuffer.buffer[1] = protocol->DslProtocolRxBufferID->pduInfo.SduDataPtr[0];
			runtime->localTxBuffer.buffer[2] = responseCode;
			runtime->localTxBuffer.PduInfo.SduDataPtr = runtime->localTxBuffer.buffer;
			runtime->localTxBuffer.PduInfo.SduLength = 3;
			runtime->localTxBuffer.status = DCM_TRANSMIT_SIGNALED; // In the DslProvideTxBuffer 'callback' this state signals it is the local buffer we are interested in sending.
			transmitResult = PduR_DcmTransmit(mainConnection->DslProtocolTx->DcmDslProtocolTxPduId, &(runtime->localTxBuffer.PduInfo));/** @req DCM115.Partially */ /* The P2ServerMin has not been implemented. */
			if (transmitResult != E_OK) {
				// TODO: What to do here?
			}
		}
	}
}

// - - - - - - - - - - -

static Std_ReturnType StartProtocolHelper(Dcm_ProtocolType protocolId) {
	Std_ReturnType ret = E_NOT_OK;
	uint16 i;

	for (i = 0; !Dcm_ConfigPtr->Dsl->DslCallbackDCMRequestService[i].Arc_EOL; i++) {
		if (Dcm_ConfigPtr->Dsl->DslCallbackDCMRequestService[i].StartProtocol != NULL) {
			ret = Dcm_ConfigPtr->Dsl->DslCallbackDCMRequestService[i].StartProtocol(protocolId);
			if (ret != E_OK) {
				break;
			}
		}
	}
	return ret;
}

// - - - - - - - - - - -

static boolean isTesterPresentCommand(const PduInfoType *rxPdu) {
	boolean ret = FALSE;
	if ((rxPdu->SduDataPtr[0] == SID_TESTER_PRESENT) && 
		(rxPdu->SduDataPtr[1] & SUPPRESS_POS_RESP_BIT) && 
		((rxPdu->SduDataPtr[1] & 0x0F)==0x00) ) {
		ret = TRUE;
	}
	return ret;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'void Dcm_Init(void)' for DSL.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DslInit(void) {
	const Dcm_DslProtocolRowType *listEntry = NULL;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

	listEntry = Dcm_ConfigPtr->Dsl->DslProtocol->DslProtocolRowList;

	while (listEntry->Arc_EOL == FALSE) {
		runtime = listEntry->DslRunTimeProtocolParameters;
		runtime->externalRxBufferStatus = NOT_IN_USE;
		runtime->externalTxBufferStatus = NOT_IN_USE;
		runtime->localRxBuffer.status = NOT_IN_USE;
		runtime->localTxBuffer.status = NOT_IN_USE;
		runtime->securityLevel = DCM_SEC_LEV_LOCKED; /** @req DCM033 */
		runtime->sessionControl = DCM_DEFAULT_SESSION; /** @req DCM034 */
		runtime->diagnosticActiveComM = FALSE;
		runtime->protocolStarted = FALSE;// OBD: close the protocol
		listEntry->DslProtocolRxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
		listEntry->DslProtocolTxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
		listEntry->DslProtocolTxBufferID->externalBufferRuntimeData->DcmRxPduId = DCM_INVALID_PDU_ID;
		runtime->localRxBuffer.DcmRxPduId = DCM_INVALID_PDU_ID;
		listEntry++;
	};

	//DcmDslRunTimeData.diagnosticRequestPending = FALSE;
	DcmDslRunTimeData.initRun = TRUE;
	// TODO: Why?
	DcmDslRunTimeData.activeProtocol = NULL;// OBD: close the current active protocol
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'void Dcm_MainFunction(void)' for DSL.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DslMain(void) {
    const Dcm_DslProtocolRowType *protocolRowEntry;
    const Dcm_DspSessionRowType *sessionRow = NULL;
    Dcm_DslRunTimeProtocolParametersType *runtime = NULL;

    protocolRowEntry = Dcm_ConfigPtr->Dsl->DslProtocol->DslProtocolRowList;
    while (protocolRowEntry->Arc_EOL == FALSE) 
	{
        runtime = protocolRowEntry->DslRunTimeProtocolParameters;
        if (runtime != NULL) 
		{
            if (runtime->sessionControl != DCM_DEFAULT_SESSION)  // Timeout if tester present is lost.
			{
                if( TRUE == runtime->S3ServerStarted ) 
				{
                    DECREMENT(runtime->S3ServerTimeoutCount);
                }
                if (runtime->S3ServerTimeoutCount == 0) 
				{
                    /* Changing session to default will stop control */
                    changeDiagnosticSession(runtime, DCM_DEFAULT_SESSION); 
                }
            }
            switch (runtime->externalTxBufferStatus)  // #### TX buffer state. ####
			{
				case NOT_IN_USE:
					break;
				case PROVIDED_TO_DSD: 
					DECREMENT(runtime->stateTimeoutCount);
					if (runtime->stateTimeoutCount == 0) 
					{
						sessionRow = getActiveSessionRow(runtime);
						runtime->stateTimeoutCount = DCM_CONVERT_MS_TO_MAIN_CYCLES(sessionRow->DspSessionP2StarServerMax); /* Reinitiate timer, see 9.2.2. */
						if (Dcm_ConfigPtr->Dsl->DslDiagResp != NULL) 
						{
							if (Dcm_ConfigPtr->Dsl->DslDiagResp->DslDiagRespForceRespPendEn == TRUE) 
							{
								if (runtime->responsePendingCount != 0) 
								{
									/** !req DCM203 suppressPosRspBit should be cleared */
									sendResponse(protocolRowEntry, DCM_E_RESPONSEPENDING);  /** @req DCM024 */
									DECREMENT( runtime->responsePendingCount );
								} 
								else 
								{
									DspCancelPendingRequests();
									sendResponse(protocolRowEntry, DCM_E_GENERALREJECT); /** @req DCM120 */
									releaseExternalRxTxBuffers(protocolRowEntry, runtime);
								}
							}
							else 
							{
								//ASLOG("DCM", "[6]\r\n");//[6]:Not configured to send response pending, now sending general reject!
								DspCancelPendingRequests();
								sendResponse(protocolRowEntry, DCM_E_GENERALREJECT);
								releaseExternalRxTxBuffers(protocolRowEntry, runtime);
							}
						}
					}
					break;
				case DSD_PENDING_RESPONSE_SIGNALED:
					// The DSD has signaled to DSL that the diagnostic response is available in the Tx buffer.
					// Make sure that response pending or general reject have not been issued,
					// if so we can not transmit to PduR because we would not know from where
					// the Tx confirmation resides later.
					if (runtime->localTxBuffer.status == NOT_IN_USE)  // Make sure that no TxConfirm could be sent by the local buffer and mixed up with this transmission.
					{
						const Dcm_DslProtocolRxType *protocolRx = NULL;
						const Dcm_DslMainConnectionType *mainConnection = NULL;
						const Dcm_DslConnectionType *connection = NULL;
						const Dcm_DslProtocolRowType *protocolRow = NULL;
						Std_ReturnType transmitResult;

						if (findRxPduIdParentConfigurationLeafs(runtime->diagReqestRxPduId, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) 
						{
							const PduIdType txPduId = mainConnection->DslProtocolTx->DcmDslProtocolTxPduId;
							//ASLOG("DCM", "[7]\r\n" );//[7]:runtime->externalTxBufferStatus enter state DCM_TRANSMIT_SIGNALED.
							runtime->externalTxBufferStatus = DCM_TRANSMIT_SIGNALED;
							transmitResult = PduR_DcmTransmit(txPduId, &runtime->diagnosticResponseFromDsd); /** @req DCM237 *//* Will trigger PduR (CanTP) to call DslProvideTxBuffer(). */
							if (transmitResult != E_OK) 
							{
								// TODO: What to do here?
							}
						} 
						else 
						{
							const PduIdType txPduId = protocolRowEntry->DslConnection->DslMainConnection->DslProtocolTx->DcmDslProtocolTxPduId;
							runtime->externalTxBufferStatus = DCM_TRANSMIT_SIGNALED;
							//ASLOG("DCM", "PduR_DcmTransmit txPduId = %d from DslMain\r\n", txPduId);
							transmitResult = PduR_DcmTransmit(txPduId, &runtime->diagnosticResponseFromDsd); /** @req DCM237 *//* Will trigger PduR (CanTP) to call DslProvideTxBuffer(). */
							if (transmitResult != E_OK) 
							{
								// TODO: What to do here?
							}
						}
					}
					break;
				case DCM_TRANSMIT_SIGNALED:
					break;
				case PROVIDED_TO_PDUR: // The valid data is being transmitted by TP-layer.
					break;
				
				default:
					break;
            }
        }
        protocolRowEntry++;
    }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'BufReq_ReturnType Dcm_StartOfReception(PduIdType dcmRxPduId,
//	PduLengthType tpSduLength, PduLengthType *rxBufferSizePtr)'.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//  This function is called called by the PduR typically when CanTp has
//  received a FF or a single frame and needs to obtain a buffer from the
//  receiver so that received data can be forwarded.
BufReq_ReturnType DslStartOfReception(PduIdType dcmRxPduId, PduLengthType tpSduLength, PduLengthType *rxBufferSizePtr)
{
    BufReq_ReturnType ret = BUFREQ_NOT_OK;
    const Dcm_DslProtocolRxType *protocolRx = NULL;
    const Dcm_DslMainConnectionType *mainConnection = NULL;
    const Dcm_DslConnectionType *connection = NULL;
    const Dcm_DslProtocolRowType *protocolRow = NULL;
    Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
    //imask_t state;
    //ASLOG("DCM", "StartOfReception !(dcmRxPduId=%d)\r\n", dcmRxPduId);
    //Irq_Save(state);
    if (findRxPduIdParentConfigurationLeafs(dcmRxPduId, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) {
        const Dcm_DslBufferType *externalRxBuffer = protocolRow->DslProtocolRxBufferID;
        if (externalRxBuffer->pduInfo.SduLength >= tpSduLength) { /** @req DCM443 */
            if ((runtime->externalRxBufferStatus == NOT_IN_USE) && (externalRxBuffer->externalBufferRuntimeData->status == BUFFER_AVAILABLE)) {
                //ASLOG("DCM", "[8]\r\n");//[8]:External buffer available!
                // ### EXTERNAL BUFFER IS AVAILABLE; GRAB IT AND REMEBER THAT WE OWN IT! ###
                externalRxBuffer->externalBufferRuntimeData->status = BUFFER_BUSY;
                runtime->diagnosticRequestFromTester.SduDataPtr = externalRxBuffer->pduInfo.SduDataPtr;
                runtime->diagnosticRequestFromTester.SduLength = tpSduLength;
                externalRxBuffer->externalBufferRuntimeData->nofBytesHandled = 0;
                runtime->externalRxBufferStatus = PROVIDED_TO_PDUR; /** @req DCM342 */
                //If external buffer is provided memorize DcmPduId
                externalRxBuffer->externalBufferRuntimeData->DcmRxPduId = dcmRxPduId;
                *rxBufferSizePtr = externalRxBuffer->pduInfo.SduLength;
                ret = BUFREQ_OK;
            } else {
            	;
            }
        } else {
            ret = BUFREQ_OVFL; /** @req DCM444 */
        }
        if (ret == BUFREQ_OK) {
            stopS3SessionTimer(runtime); /** @req DCM141 */
        }
    }
    //Irq_Restore(state);
    return ret;
}

BufReq_ReturnType DslCopyDataToRxBuffer(PduIdType dcmRxPduId, PduInfoType *pduInfoPtr, PduLengthType *rxBufferSizePtr)
{
    BufReq_ReturnType returnCode = BUFREQ_NOT_OK;
    const Dcm_DslProtocolRxType *protocolRx = NULL;
    const Dcm_DslMainConnectionType *mainConnection = NULL;
    const Dcm_DslConnectionType *connection = NULL;
    const Dcm_DslProtocolRowType *protocolRow = NULL;
    Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
    //imask_t state;
    //Irq_Save(state);

    if (findRxPduIdParentConfigurationLeafs(dcmRxPduId, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) {
        const Dcm_DslBufferType *externalRxBuffer = protocolRow->DslProtocolRxBufferID;
        if ((PROVIDED_TO_PDUR == runtime->externalRxBufferStatus ) && (externalRxBuffer->externalBufferRuntimeData->DcmRxPduId == dcmRxPduId)){
            /* Buffer is provided to PDUR. Copy data to buffer */
            uint8 *destPtr = &(runtime->diagnosticRequestFromTester.SduDataPtr[externalRxBuffer->externalBufferRuntimeData->nofBytesHandled]);
            if( 0 == pduInfoPtr->SduLength ) {
                /* Just polling remaining buffer size */
                returnCode = BUFREQ_OK;
            } else if( pduInfoPtr->SduLength <= (externalRxBuffer->pduInfo.SduLength - externalRxBuffer->externalBufferRuntimeData->nofBytesHandled) ) {
                /* Enough room in buffer. Copy data. */
                /** @req DCM443 */
                memcpy(destPtr, pduInfoPtr->SduDataPtr, pduInfoPtr->SduLength);
                /* Inc nof bytes handled byte */
                externalRxBuffer->externalBufferRuntimeData->nofBytesHandled += pduInfoPtr->SduLength;
                returnCode = BUFREQ_OK;
            } else {
                /* Length exceeds number of bytes left in buffer */
                //ASLOG("DCM", "[9]\r\n");//[9]:DCM_E_INTERFACE_BUFFER_OVERFLOW
                returnCode = BUFREQ_NOT_OK;
            }
                *rxBufferSizePtr =
                            externalRxBuffer->pduInfo.SduLength - externalRxBuffer->externalBufferRuntimeData->nofBytesHandled;
        } else if ((runtime->localRxBuffer.status == PROVIDED_TO_PDUR) && (runtime->localRxBuffer.DcmRxPduId == dcmRxPduId)){
            /* Local buffer provided to pdur */
            if(0 == pduInfoPtr->SduLength) {
                /* Just polling remaining buffer size */
                returnCode = BUFREQ_OK;
            } else if(pduInfoPtr->SduLength <= (DCM_DSL_LOCAL_BUFFER_LENGTH - runtime->localRxBuffer.nofBytesHandled)) {
                uint8 *destPtr = &(runtime->localRxBuffer.PduInfo.SduDataPtr[runtime->localRxBuffer.nofBytesHandled]);
                memcpy(destPtr, pduInfoPtr->SduDataPtr, pduInfoPtr->SduLength);
                runtime->localRxBuffer.nofBytesHandled += pduInfoPtr->SduLength;
                returnCode = BUFREQ_OK;
            } else {
                /* Length exceeds buffer size */
                //ASLOG("DCM", "[10]\r\n");//[10]:DCM_E_INTERFACE_BUFFER_OVERFLOW
                returnCode = BUFREQ_NOT_OK;
            }
            *rxBufferSizePtr = DCM_DSL_LOCAL_BUFFER_LENGTH - runtime->localRxBuffer.nofBytesHandled;
        }
    }
    //Irq_Restore(state);

    return returnCode;

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'void Dcm_TpRxIndication(PduIdType dcmRxPduId, NotifResultType result)'.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 	This function is called called by the PduR typically when CanTp has
//	received the diagnostic request, copied it to the provided buffer and need to indicate
//	this to the DCM (DSL) module via proprietary API.

void DslTpRxIndicationFromPduR(PduIdType dcmRxPduId, NotifResultType result) {
    const Dcm_DslProtocolRxType *protocolRx = NULL;
    const Dcm_DslMainConnectionType *mainConnection = NULL;
    const Dcm_DslConnectionType *connection = NULL;
    const Dcm_DslProtocolRowType *protocolRow = NULL;
    const Dcm_DspSessionRowType *sessionRow = NULL;
    Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
    Std_ReturnType higherLayerResp;

    if (findRxPduIdParentConfigurationLeafs(dcmRxPduId, &protocolRx, &mainConnection, &connection, &protocolRow, &runtime)) {
        const Dcm_DslBufferType *externalRxBuffer = protocolRow->DslProtocolRxBufferID;
        if ((runtime->externalRxBufferStatus == PROVIDED_TO_PDUR) && (externalRxBuffer->externalBufferRuntimeData->DcmRxPduId == dcmRxPduId)) 
		{
            boolean receivedLenOK =
                    (externalRxBuffer->externalBufferRuntimeData->nofBytesHandled == runtime->diagnosticRequestFromTester.SduLength) ||
                    (0 == runtime->diagnosticRequestFromTester.SduLength);
            if ( result == NTFRSLT_OK && receivedLenOK )  
			{
                if ((isTesterPresentCommand(&(protocolRow->DslProtocolRxBufferID->pduInfo)))&&(2 == runtime->diagnosticRequestFromTester.SduLength)) 
				{
                    startS3SessionTimer(runtime, protocolRow);
                    runtime->externalRxBufferStatus = NOT_IN_USE;
                    externalRxBuffer->externalBufferRuntimeData->DcmRxPduId = DCM_INVALID_PDU_ID;
                    protocolRow->DslProtocolRxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
                } 
				else 
				{
                    if (runtime->protocolStarted == FALSE) 
					{
                        //if there is no active protocol,then start the current protocol
                        if(DcmDslRunTimeData.activeProtocol == NULL)
						{
                            higherLayerResp = StartProtocolHelper(protocolRow->DslProtocolID);
                            if (higherLayerResp == E_OK) 
							{
                                runtime->protocolStarted = TRUE;
                                DcmDslRunTimeData.activeProtocol = protocolRow;
                            }
                        }
                        else
						{
                            /*if the priority of the current protocol is lower than the priority of the active protocol, we do nothing.*/
                            runtime->externalRxBufferStatus = NOT_IN_USE;
                            protocolRow->DslProtocolRxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
                        }
                    }
                    if (runtime->protocolStarted == TRUE) 
					{
                        sessionRow = getActiveSessionRow(runtime);
                        runtime->stateTimeoutCount = DCM_CONVERT_MS_TO_MAIN_CYCLES(sessionRow->DspSessionP2ServerMax); /* See 9.2.2. */
                        runtime->externalRxBufferStatus = PROVIDED_TO_DSD;
                        if (runtime->externalTxBufferStatus == NOT_IN_USE) 
						{
                            //ASLOG("DCM", "[11]\r\n");//[11]:External Tx buffer available, we can pass it to DSD.
                        } 
						else 
						{
                            //ASLOG("DCM", "[12]\r\n");//[12]:External buffer not available, a response is being transmitted?
                        }
                        if( 0 == runtime->diagnosticRequestFromTester.SduLength ) {
                            runtime->diagnosticRequestFromTester.SduLength = externalRxBuffer->externalBufferRuntimeData->nofBytesHandled;
                        }
                        runtime->externalTxBufferStatus = PROVIDED_TO_DSD;
                        runtime->responsePendingCount = Dcm_ConfigPtr->Dsl->DslDiagResp->DslDiagRespMaxNumRespPend;
                        runtime->diagnosticResponseFromDsd.SduDataPtr = protocolRow->DslProtocolTxBufferID->pduInfo.SduDataPtr;
                        runtime->diagnosticResponseFromDsd.SduLength = protocolRow->DslProtocolTxBufferID->pduInfo.SduLength;
                       runtime->diagReqestRxPduId = dcmRxPduId;
                        //ASLOG("DCM", "dcmRxPduId=%d,runtime->diagnosticRequestFromTester.SduDataPtr[2]  %x\r\n ",dcmRxPduId,runtime->diagnosticRequestFromTester.SduDataPtr[2]);
                        DsdDslDataIndication(  
                            &(runtime->diagnosticRequestFromTester),
                            protocolRow->DslProtocolSIDTable,	
                            protocolRx->DslProtocolAddrType,
                            mainConnection->DslProtocolTx->DcmDslProtocolTxPduId,
                            &(runtime->diagnosticResponseFromDsd),
                            dcmRxPduId);
                    }
                }
            } else { /** @req DCM344 */
                /* The indication was not equal to NTFRSLT_OK or the length did not match,
                 * release the resources and no forward to DSD.*/
                if(!receivedLenOK) {
                    /* Number of bytes received does not match the original request */
                    //ASLOG("DCM", "[13]\r\n");//[13]:DCM_E_TP_LENGTH_MISMATCH
                }
                DslResetSessionTimeoutTimer(); /** @req DCM141 */
                runtime->externalRxBufferStatus = NOT_IN_USE;
                externalRxBuffer->externalBufferRuntimeData->DcmRxPduId = DCM_INVALID_PDU_ID;
                protocolRow->DslProtocolRxBufferID->externalBufferRuntimeData->status = BUFFER_AVAILABLE;
            }
        } 
		else 
        {
			//ASLOG("DCM", "[14]\r\n");//[14]:DCM_E_TP_LENGTH_MISMATCH
        }
    }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'BufReq_ReturnType Dcm_CopyTxData(PduIdType dcmTxPduId,
//		PduInfoType *pduInfoPtr, RetryInfoType *retryInfoPtr, PduLengthType *txDataCntPtr)'.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//  This TX-buffer request is likely triggered by the transport layer (i.e. CanTp)
//  after PduR_DcmTransmit() has been called (via PduR to CanTp) indicating that something
//  is to be sent. The PduR_DcmTransmit() call is done from the DSL main function when
//  it has detected that the pending request has been answered by DSD
//  (or any other module?).

BufReq_ReturnType DslCopyTxData(PduIdType dcmTxPduId, PduInfoType *pduInfoPtr, RetryInfoType *periodData, PduLengthType *txDataCntPtr)
{
	BufReq_ReturnType ret = BUFREQ_NOT_OK;
	const Dcm_DslProtocolTxType *protocolTx = NULL;
	const Dcm_DslMainConnectionType *mainConnection = NULL;
	const Dcm_DslConnectionType *connection = NULL;
	const Dcm_DslProtocolRowType *protocolRow = NULL;
	Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
	(void) periodData;//Not used

	//ASLOG("DCM", "DslProvideTxBuffer=%d\r\n", dcmTxPduId);
	if (findTxPduIdParentConfigurationLeafs(dcmTxPduId, &protocolTx, &mainConnection, &connection, &protocolRow, &runtime)) {
		const Dcm_DslBufferType *externalTxBuffer = protocolRow->DslProtocolTxBufferID;
		ret = BUFREQ_OK;
		switch (runtime->externalTxBufferStatus) { // ### EXTERNAL TX BUFFER ###
		case DCM_TRANSMIT_SIGNALED:
			externalTxBuffer->externalBufferRuntimeData->nofBytesHandled = 0;
			runtime->externalTxBufferStatus = PROVIDED_TO_PDUR; /** @req DCM349 */
			break;
		case PROVIDED_TO_PDUR:
			break;
		default:
			//ASLOG("DCM", "[15]\r\n");//[15]:DCM_TRANSMIT_SIGNALED was not signaled in the external buffer
			ret = BUFREQ_NOT_OK;
			break;
		}
		if( BUFREQ_OK == ret ) 
		{
			if( 0 == pduInfoPtr->SduLength ) 
			{
				/* Just polling size of data left to send */
			} 
			else if( pduInfoPtr->SduLength > (runtime->diagnosticResponseFromDsd.SduLength - externalTxBuffer->externalBufferRuntimeData->nofBytesHandled) ) 
			{
				/* Length exceeds the number of bytes still to be sent. */
				ret = BUFREQ_NOT_OK;
			} 
			else 
			{
				/** @req DCM346 */ /* Length verification is already done if this state is reached. */
				memcpy(pduInfoPtr->SduDataPtr, &runtime->diagnosticResponseFromDsd.SduDataPtr[externalTxBuffer->externalBufferRuntimeData->nofBytesHandled], pduInfoPtr->SduLength);
				externalTxBuffer->externalBufferRuntimeData->nofBytesHandled += pduInfoPtr->SduLength;
			}
			*txDataCntPtr = runtime->diagnosticResponseFromDsd.SduLength - externalTxBuffer->externalBufferRuntimeData->nofBytesHandled;
		} 
		else if (ret == BUFREQ_NOT_OK) 
		{
			ret = BUFREQ_OK;
			switch (runtime->localTxBuffer.status) { // ### LOCAL TX BUFFER ###
			case DCM_TRANSMIT_SIGNALED: {
				runtime->localTxBuffer.PduInfo.SduDataPtr = runtime->localTxBuffer.buffer;
				runtime->localTxBuffer.nofBytesHandled = 0;
				runtime->localTxBuffer.status = PROVIDED_TO_PDUR; // Now the DSL should not touch this Tx-buffer anymore.
				break;
			}
			case PROVIDED_TO_PDUR:
				break;
			default:
				//ASLOG("DCM", "[16]\r\n");//[16]:DCM_TRANSMIT_SIGNALED was not signaled for the local buffer either
				ret = BUFREQ_NOT_OK;
				break;
			}
			if( BUFREQ_OK == ret ) {
				if( 0 == pduInfoPtr->SduLength ) {
					/* Just polling size of data left to send */
				} else if( pduInfoPtr->SduLength > (runtime->localTxBuffer.PduInfo.SduLength - runtime->localTxBuffer.nofBytesHandled) ) {
					/* Length exceeds the number of bytes still to be sent. */
					ret = BUFREQ_NOT_OK;
				} else {
					memcpy(pduInfoPtr->SduDataPtr, &runtime->localTxBuffer.PduInfo.SduDataPtr[runtime->localTxBuffer.nofBytesHandled], pduInfoPtr->SduLength);
					runtime->localTxBuffer.nofBytesHandled += pduInfoPtr->SduLength;
				}
				*txDataCntPtr = runtime->localTxBuffer.PduInfo.SduLength - runtime->localTxBuffer.nofBytesHandled;
			}
		}
	}
	return ret;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//	Implements 'void Dcm_TpTxConfirmation(PduIdType dcmTxPduId, NotifResultType result))'.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// 	This function is called by the PduR (which has been trigged by i.e. CanTp)
// 	when a transmission has been successfully finished, have had errors or
// 	is even stopped.

void DslTpTxConfirmation(PduIdType dcmTxPduId, NotifResultType result) {

    const Dcm_DslProtocolTxType *protocolTx = NULL;
    const Dcm_DslMainConnectionType *mainConnection = NULL;
    const Dcm_DslConnectionType *connection = NULL;
    const Dcm_DslProtocolRowType *protocolRow = NULL;
    Dcm_DslRunTimeProtocolParametersType *runtime = NULL;
    //imask_t state;

    //ASLOG("DCM", " DslTxConfirmation=%d, result=%d\r\n", dcmTxPduId, result);
    if (findTxPduIdParentConfigurationLeafs(dcmTxPduId, &protocolTx, &mainConnection, &connection, &protocolRow, &runtime)) {
        boolean externalBufferReleased = FALSE;
        const Dcm_DslBufferType *externalTxBuffer = protocolRow->DslProtocolTxBufferID;
        // Free the buffer and free the Pdu runtime data buffer.
        //Irq_Save(state);
        switch (runtime->externalTxBufferStatus) { // ### EXTERNAL TX BUFFER ###
        case PROVIDED_TO_PDUR: {
            if( runtime->diagnosticResponseFromDsd.SduLength != externalTxBuffer->externalBufferRuntimeData->nofBytesHandled ) {
                //ASLOG("DCM", "[17]\r\n");//[17]:DCM_E_TP_LENGTH_MISMATCH
            }
            startS3SessionTimer(runtime, protocolRow); /** @req DCM141 */
            releaseExternalRxTxBuffers(protocolRow, runtime); /** @req DCM118 *//** @req DCM352 *//** @req DCM353 *//** @req DCM354 */
            externalBufferReleased = TRUE;
        //	DEBUG( DEBUG_MEDIUM, "Released external buffer OK!\r\n");
            DsdDataConfirmation(mainConnection->DslProtocolTx->DcmDslProtocolTxPduId, result); /** @req DCM117 *//** @req DCM235 */
            break;
        	}
        	default:
        	break;
        }
        if (!externalBufferReleased) {
            switch (runtime->localTxBuffer.status) { // ### LOCAL TX BUFFER ###
            case PROVIDED_TO_PDUR:
                //ASLOG("DCM", "[18]\r\n");//[18]:Released local buffer buffer OK!
                runtime->localTxBuffer.status = NOT_IN_USE;
                break;
            default:
                //ASLOG("DCM", "[19]\r\n");//[19]:DslTxConfirmation could not release external or local buffer!
                break;
            }
        }
        //Irq_Restore(state);
    }
}
